﻿using System;
using ParserGenerator.Exceptions;
using ParserGenerator.SyntacticAnalysis;

namespace ParserGenerator.GrammarConstruction
{
    [Serializable]
    public sealed class GrammarTerminalSymbol : GrammarSymbol
    {
        public string Value { get; internal set; }
        public string Text { get; internal set; }

        public TokenDeclarationKind Kind { get; internal set; }
        public bool IsEndMarker => Kind == TokenDeclarationKind.EndMarker;
        public bool IsLayoutMarker => Kind == TokenDeclarationKind.LayoutMarker;
        public bool IsHiddenToken => Kind == TokenDeclarationKind.HiddenToken;
        public bool IsKeyword => Kind == TokenDeclarationKind.Keyword;
        public bool IsReservedWord => Kind == TokenDeclarationKind.ReservedWord;
        public bool IsLiteral => Value != null;

        public int? Precedence { get; private set; }
        public OperatorAssociativity? Associativity { get; private set; }
        public ShiftReduceResolution? Resolution { get; private set; }

        internal GrammarTerminalSymbol()
        {
        }

        internal void AssignOperatorLevel(int prec, OperatorAssociativity assoc)
        {
            if (Precedence == null)
            {
                Precedence = prec;
                Associativity = assoc;
            }
            else
            {
                string message = string.Format(SR.OpPrecedenceSpecified, Name);
                GrammarErrorException e = new GrammarErrorException(message);
                e.AddLocation(Context);
                throw e;
            }
        }

        internal void AssignResolution(ShiftReduceResolution resolution)
        {
            if (Resolution == null)
                Resolution = resolution;
            else
            {
                string message = string.Format(SR.ShiftReduceResolutionSpecified, Name);
                GrammarErrorException e = new GrammarErrorException(message);
                e.AddLocation(Context);
                throw e;
            }
        }
    }
}
